package com.swu.cx.alwayslearning.myretrofit

import okhttp3.Call
import okhttp3.FormBody
import okhttp3.HttpUrl
import okhttp3.Request
import java.lang.reflect.Method

// 记录请求类型、参数、完整地址
class ServiceMethod private constructor(private val builder: Builder){

    private val callFactory: Call.Factory = builder.retrofit.callFactory
    private val baseUrl: HttpUrl = builder.retrofit.baseUrl

    private val httpMethod: String = builder.httpMethod!!
    private val relativeUrl: String = builder.relativeUrl!!
    private val hasBody: Boolean = builder.hasBody
    private val parameterHandlers = builder.parameterHandlers

    private var formBuild: FormBody.Builder? = null

    private var urlBuilder: HttpUrl.Builder? = null
    init {
        if (hasBody) {
            formBuild = FormBody.Builder()
        }
    }

    fun invoke(args: Array<out Any>): Call {
        for (i in parameterHandlers.indices) {
            parameterHandlers[i]?.apply(this, args[i] as String)
        }
        if (urlBuilder == null) {
            urlBuilder = baseUrl.newBuilder(relativeUrl)
        }
        val url = urlBuilder?.build()
        val formBody = formBuild?.build()
        val request = Request.Builder()
            .url(url)
            .method(httpMethod, formBody)
            .build()
        return callFactory.newCall(request)
    }

    fun addQueryParameter(key: String, value: String) {
        if (urlBuilder == null) {
            urlBuilder = baseUrl.newBuilder(relativeUrl)
        }
        urlBuilder?.addQueryParameter(key, value)
    }

    fun addFieldParameter(key: String, value: String) {
        formBuild?.add(key, value)
    }

    class Builder constructor(
        val retrofit: MyRetrofit,
        private val method: Method
    ) {
        var hasBody: Boolean = false
            private set
        var relativeUrl: String? = null
            private set
        var httpMethod: String? = null
            private set
        private val annotations: Array<Annotation> = method.annotations
        private val paramAnnotations: Array<Array<Annotation>> = method.parameterAnnotations
        val parameterHandlers = arrayOfNulls<ParameterHandler>(paramAnnotations.size)

        fun build(): ServiceMethod {
            // 1.解析方法上的注解，只处理POST和GET
            parseMethodAnnotation()
            // 2.解析方法参数上的注解
            parseParamAnnotation()
            return ServiceMethod(this)
        }

        private fun parseMethodAnnotation() {
            for (methodAnnotation in annotations) {
                if (methodAnnotation is POST) {
                    this.httpMethod = "POST"
                    this.relativeUrl = (methodAnnotation as POST).path
                    this.hasBody = true
                } else if(methodAnnotation is GET) {
                    this.httpMethod = "GET"
                    this.relativeUrl = (methodAnnotation as GET).path
                    this.hasBody = false
                }
            }
        }

        private fun parseParamAnnotation() {

            for(i in paramAnnotations.indices) {
                // 每个参数上的注解
                val annotations = paramAnnotations[i]
                for (annotation in annotations) {
                    if (annotation is Field) {
                        parameterHandlers[i] = ParameterHandler.FieldParameterHandler(annotation.value)
                    } else if(annotation is Query) {
                        parameterHandlers[i] = ParameterHandler.QueryParameterHandler(annotation.value)
                    }
                }
            }
        }

    }

}